package com.itheima.security.distributed.uaa.config;

import com.itheima.security.distributed.uaa.service.AuthUserDetails;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: yangguoxiong
 * @date: 2022/3/8 15:05
 * @description: token增强器(用于扩展jwt,增加附加信息)
 */
@Component
@AllArgsConstructor
public class JwtTokenEnhancer implements TokenEnhancer {

    private final JwtAccessTokenConverter jwtAccessTokenConverter;
    private final RedisTemplate redisTemplate;


    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        AuthUserDetails principal = (AuthUserDetails) authentication.getPrincipal();

        //token参数增强,添加附加信息
        Map<String, Object> info = new HashMap<>();
        info.put("mark", "yang");
        info.put("userId", principal.getUserId());
        info.put("username", principal.getUsername());
        info.put("roleName", principal.getRoleName());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);

        /**
         * 当前这个增强器是先在JwtAccessTokenConverter之前执行的 -> 看AuthorizationServer类的tokenService()中,setTokenEnhancers的顺序
         * 所以,下面的操作,在JwtAccessTokenConverter.enhance方法中会重复执行一次,生成的OAuth2AccessToken也是相同的.在这里调一次的目的,是为了
         * 能把这个相同的OAuth2AccessToken保存到redis中,后面在gateway鉴权的时候,判断redis中是否有这个key,如果没有就报错令牌失效,就有获取到令牌信息做其他处理.
         */
        OAuth2AccessToken oAuth2AccessToken = jwtAccessTokenConverter.enhance(accessToken, authentication);
        //将jwt保存到redis中

        redisTemplate.opsForValue().set(oAuth2AccessToken.getValue(), oAuth2AccessToken.getValue(), oAuth2AccessToken.getExpiresIn(), TimeUnit.SECONDS);

        return accessToken;
    }
}
